package com.channel.modules.security.secutiry;

import cn.hutool.core.date.DateField;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.crypto.digest.DigestUtil;
import com.channel.modules.security.config.bean.SecurityProperties;
import com.commons.utils.RedisUtils;
import io.jsonwebtoken.*;
import io.jsonwebtoken.io.Decoders;
import io.jsonwebtoken.security.Keys;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.userdetails.User;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;
import java.security.Key;
import java.util.ArrayList;
import java.util.Date;
import java.util.concurrent.TimeUnit;

@Component
public class TokenProvider implements InitializingBean {

    private final SecurityProperties properties;
    private final RedisUtils redisUtils;
    public static final String AUTHORITIES_KEY="user";
    private JwtParser jwtParser;
    private JwtBuilder jwtBuilder;

    @Autowired
    public TokenProvider(SecurityProperties properties, RedisUtils redisUtils) {
        this.properties = properties;
        this.redisUtils = redisUtils;
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        byte[] keyBytes = Decoders.BASE64.decode(properties.getBase64Secret());
        Key key = Keys.hmacShaKeyFor(keyBytes);
        jwtParser = Jwts.parserBuilder()
                .setSigningKey(key)
                .build();
        jwtBuilder = Jwts.builder()
                .signWith(key, SignatureAlgorithm.HS512);
    }

    /**
     * 创建token 设置永不过期
     * token 的时间有效性转到redis维护
     */
    public String createToken(Authentication authentication) {
        //加入ID确保生成key都不一致
        return jwtBuilder.setId(IdUtil.simpleUUID())
                .claim(AUTHORITIES_KEY,authentication.getName())
                .setSubject(authentication.getName())
                .compact();

    }

    /**
     * 根据token 获取鉴权信息
     * @param token
     * @return
     */
    Authentication getAuthentication(String token) {
        Claims claims = getClaims(token);
        User principal = new User(claims.getSubject(), "******", new ArrayList<>());
        return new UsernamePasswordAuthenticationToken(principal,token,new ArrayList<>());

    }

    public Claims getClaims(String token) {
        return jwtParser.parseClaimsJws(token).getBody();
    }

    /**
     * 需要检查的token
     * @param token
     */
    public void checkRenewal(String token){
        //判断是否要续期token，计算token的过期时间
        long time=redisUtils.getExpire(properties.getOnlineKey()+token)*1000;
        Date expireDate=DateUtil.offset(new Date(), DateField.MILLISECOND,(int)time);
        //判断当前时间与过期时间的时间差
        long differ=expireDate.getTime()-System.currentTimeMillis();
        if(differ<=properties.getDetect()){
            long renew=time+properties.getRenew();
            redisUtils.expire(properties.getOnlineKey()+token,renew, TimeUnit.MILLISECONDS);
        }
    }

    public String getToken(HttpServletRequest request){
      final   String requestHeader = request.getHeader(properties.getHeader());
      if(requestHeader!=null&&requestHeader.startsWith(properties.getTokenStartWith())){
          return requestHeader.substring(7);
      }
      return null;
    }

    /**
     * 获取登录用户的rediskey
     */
    public String loginKey(String token){
        Claims claims = getClaims(token);
        String md5Token = DigestUtil.md5Hex(token);
        return properties.getOnlineKey()+claims.getSubject()+"-"+md5Token;
    }
}
